using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace ControlLibrary.StyledTextBox
{
    public class AlphaTextBox : TextBox
    {
        private AlphaPanel APanel;
        private Timer BlinkCaretTimer;
        private PointF CaretPosition;
        private Bitmap ClientRegionBitmap;
        private bool DrawCaret;
        private int InternalAlphaAmount;
        private Color InternalAlphaBackColor;
        private bool InternalBGSet;
        protected internal Delegate STClientDel;
        private bool SelectingText;
        private Utilities TBUtils;
        private Container components;

        public AlphaTextBox()
        {
            InitializeComponent();
        }

        [Browsable(true), Description("The Alpha Amount, or transparency amount, applied to the background."), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Category("Appearance")]
        public int AlphaAmount
        {
            get { return InternalAlphaAmount; }
            set
            {
                if ((value > 0xff) || (value < 0))
                {
                    throw new Exception("AlphaAmount must be between 0 and 255!");
                }
                InternalAlphaAmount = value;
                UpdateRegion();
            }
        }

        [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Category("Appearance"), Description("The visible background color for the AlphaTextBox.")]
        public Color AlphaBackColor
        {
            get { return InternalAlphaBackColor; }
            set
            {
                InternalAlphaBackColor = value;
                UpdateRegion();
            }
        }

        public override Color BackColor
        {
            get { return base.BackColor; }
            set
            {
                if (!InternalBGSet)
                {
                    base.BackColor = Color.Transparent;
                }
                else
                {
                    base.BackColor = value;
                }
            }
        }

        public override bool Multiline
        {
            get { return base.Multiline; }
            set
            {
                base.Multiline = value;
                UpdateRegion();
            }
        }

        private void BlinkCaretTimer_Elapsed(object sender, EventArgs eventArgs)
        {
            if (!SelectingText && (SelectionLength > 0))
            {
                SelectingText = true;
                DrawCaret = false;
                UpdateRegion();
            }
            else if (!SelectingText)
            {
                DrawCaret = !DrawCaret;
                DrawCaretToBitmap();
            }
        }

        private Bitmap CaptureClientRegion()
        {
            InternalBGSet = true;
            var image = new Bitmap(base.Width, base.Height);
            BackColor = AlphaBackColor;
            Graphics graphics = Graphics.FromImage(image);
            IntPtr hdc = graphics.GetHdc();
            TBUtils.SendMessageToMaster(TBUtils.WM_PRINT, hdc, (IntPtr) (TBUtils.PRF_CLIENT | TBUtils.PRF_ERASEBKGND), -1);
            graphics.ReleaseHdc(hdc);
            graphics.Dispose();
            InternalBGSet = false;
            BackColor = Color.Transparent;
            return image;
        }

        private Bitmap CaptureNonClientRegion()
        {
            var image = new Bitmap(base.Width, base.Height);
            Graphics graphics = Graphics.FromImage(image);
            IntPtr hdc = graphics.GetHdc();
            TBUtils.SendMessageToMaster(TBUtils.WM_PRINT, hdc, (IntPtr) (TBUtils.PRF_NONCLIENT | TBUtils.PRF_ERASEBKGND), -1);
            graphics.ReleaseHdc(hdc);
            graphics.Dispose();
            return image;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void DrawCaretToBitmap()
        {
            Graphics graphics = Graphics.FromImage(APanel.BackgroundImage);
            if (DrawCaret)
            {
                graphics.FillRectangle(new SolidBrush(ForeColor), CaretPosition.X, CaretPosition.Y, Font.SizeInPoints/5f, base.FontHeight);
            }
            else
            {
                APanel.BackgroundImage = (Bitmap) ClientRegionBitmap.Clone();
            }
            APanel.Refresh();
        }

        public Bitmap GetScreenShot()
        {
            Bitmap image = CaptureNonClientRegion();
            Bitmap bitmap2 = TBUtils.MapColors(AlphaBackColor, Color.FromArgb(AlphaAmount, AlphaBackColor), CaptureClientRegion(), true);
            Graphics graphics = Graphics.FromImage(image);
            graphics.DrawImage(bitmap2, 0, 0, base.ClientSize.Width, base.ClientSize.Height);
            graphics.Dispose();
            bitmap2.Dispose();
            return image;
        }

        private void InitializeComponent()
        {
            base.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            components = new Container();
            STClientDel = new SMDel(DefWndProc);
            TBUtils = new Utilities(STClientDel, this);
            InternalBGSet = false;
            DrawCaret = false;
            SelectingText = false;
            APanel = new AlphaPanel(this);
            BlinkCaretTimer = new Timer();
            BlinkCaretTimer.Interval = 500;

            BlinkCaretTimer.Tick += BlinkCaretTimer_Elapsed;

            BackColor = Color.Transparent;
            base.Controls.Add(APanel);
        }

        protected override void OnBorderStyleChanged(EventArgs e)
        {
            base.OnBorderStyleChanged(e);
            UpdateRegion();
        }

        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            UpdateRegion();
        }

        protected override void OnForeColorChanged(EventArgs e)
        {
            if (!InternalBGSet)
            {
                base.OnForeColorChanged(e);
                UpdateRegion();
            }
        }

        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            BlinkCaretTimer.Start();
            UpdateRegion();
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            if ((((e.KeyCode == Keys.Left) || (e.KeyCode == Keys.Up)) || ((e.KeyCode == Keys.Down) || (e.KeyCode == Keys.Right))) ||
                (((e.KeyCode == Keys.Next) || (e.KeyCode == Keys.Prior)) || ((e.KeyCode == Keys.Home) || (e.KeyCode == Keys.End))))
            {
                DrawCaret = true;
                if (!BlinkCaretTimer.Enabled)
                {
                    BlinkCaretTimer.Start();
                }
                UpdateRegion();
            }
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e);
            if ((((e.KeyCode == Keys.Left) || (e.KeyCode == Keys.Up)) || ((e.KeyCode == Keys.Down) || (e.KeyCode == Keys.Right))) ||
                (((e.KeyCode == Keys.Next) || (e.KeyCode == Keys.Prior)) || ((e.KeyCode == Keys.Home) || (e.KeyCode == Keys.End))))
            {
                UpdateRegion();
            }
            else if ((SelectionLength == 0) && SelectingText)
            {
                SelectingText = false;
                DrawCaret = true;
                if (!BlinkCaretTimer.Enabled)
                {
                    BlinkCaretTimer.Start();
                }
                UpdateRegion();
            }
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            DrawCaret = false;
            UpdateRegion();
            BlinkCaretTimer.Stop();
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if ((SelectionLength == 0) && SelectingText)
            {
                SelectingText = false;
                DrawCaret = true;
            }
            if (!BlinkCaretTimer.Enabled)
            {
                BlinkCaretTimer.Start();
            }
            UpdateRegion();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            APanel.Size = base.ClientSize;
            UpdateRegion();
        }

        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            DrawCaret = true;
            if (!BlinkCaretTimer.Enabled)
            {
                BlinkCaretTimer.Start();
            }
            UpdateRegion();
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            APanel.Visible = base.Visible;
        }

        private void SetCaret()
        {
            if (Text == "")
            {
                CaretPosition = new PointF(2f, 2f);
                DrawCaretToBitmap();
            }
            else
            {
                int num = base.SelectionStart + SelectionLength;
                bool flag = false;
                float width = 0f;
                string text = "";
                int num3 = 0;
                if ((num == TextLength) && (Text[Text.Length - 1] != '\n'))
                {
                    num--;
                }
                else if ((num == TextLength) && (Text[Text.Length - 1] == '\n'))
                {
                    flag = true;
                    num--;
                }
                num3 = ((IntPtr) TBUtils.SendMessageToMaster(TBUtils.EM_POSFROMCHAR, (IntPtr) num, IntPtr.Zero, 1)).ToInt32();
                if (base.SelectionStart != TextLength)
                {
                    CaretPosition = new PointF((num3 & 0xff), ((num3 >> 0x10) & 0xff));
                    DrawCaretToBitmap();
                }
                else
                {
                    Graphics graphics = base.CreateGraphics();
                    text = Text[num].ToString();
                    width = graphics.MeasureString(text, Font).Width;
                    CaretPosition = new PointF((num3 & 0xff) + (width/2f), ((num3 >> 0x10) & 0xff));
                    graphics.Dispose();
                    if (flag)
                    {
                        CaretPosition = new PointF(2f, CaretPosition.Y + base.FontHeight);
                    }
                    DrawCaretToBitmap();
                }
            }
        }

        private void UpdateRegion()
        {
            if (ClientRegionBitmap != null)
            {
                ClientRegionBitmap.Dispose();
            }
            ClientRegionBitmap = TBUtils.MapColors(AlphaBackColor, Color.FromArgb(AlphaAmount, AlphaBackColor), CaptureClientRegion(), true);
            APanel.BackgroundImage = (Bitmap) ClientRegionBitmap.Clone();
            SetCaret();
            GC.Collect();
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (((m.Msg == TBUtils.WM_HSCROLL) || (m.Msg == TBUtils.WM_VSCROLL)) || (m.Msg == TBUtils.WM_MOUSEWHEEL))
            {
                DrawCaret = false;
                BlinkCaretTimer.Stop();
                UpdateRegion();
            }
            else if ((m.Msg == TBUtils.WM_MOUSEMOVE) && (((int) m.WParam) != 0))
            {
                DrawCaret = false;
                SelectingText = true;
                UpdateRegion();
            }
        }

        #region Nested type: AlphaPanel

        private class AlphaPanel : Panel
        {
            private readonly AlphaTextBox MasterTb;
            private readonly Utilities PUtils;
            protected internal readonly Delegate ToMasterDel;

            protected internal AlphaPanel(AlphaTextBox Master)
            {
                MasterTb = Master;
                base.Size = Master.Size;
                base.Location = new Point(0, 0);
                ToMasterDel = MasterTb.STClientDel;
                base.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
                base.SetStyle(ControlStyles.UserPaint, true);
                base.SetStyle(ControlStyles.DoubleBuffer, true);
                base.SetStyle(ControlStyles.Selectable, false);
                PUtils = new Utilities(ToMasterDel, MasterTb);
            }

            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);
                if (m.Msg == PUtils.WM_MOUSEMOVE)
                {
                    PUtils.SendMessageToMaster(m.Msg, m.WParam, m.LParam, -1);
                }
                else if (m.Msg == PUtils.WM_LBUTTONDOWN)
                {
                    PUtils.SendMessageToMaster(m.Msg, m.WParam, m.LParam, -1);
                }
                else if (m.Msg == PUtils.WM_LBUTTONUP)
                {
                    PUtils.SendMessageToMaster(m.Msg, m.WParam, m.LParam, -1);
                }
                else if (m.Msg == PUtils.WM_LBUTTONDBLCLK)
                {
                    PUtils.SendMessageToMaster(m.Msg, m.WParam, m.LParam, -1);
                }
                else if (m.Msg == PUtils.WM_MOUSELEAVE)
                {
                    PUtils.SendMessageToMaster(m.Msg, m.WParam, m.LParam, -1);
                }
                else if (m.Msg == PUtils.WM_RBUTTONDOWN)
                {
                    PUtils.SendMessageToMaster(m.Msg, m.WParam, m.LParam, -1);
                }
                else if (m.Msg == PUtils.WM_MOUSEACTIVATE)
                {
                    PUtils.SendMessageToMaster(m.Msg, m.WParam, m.LParam, -1);
                }
            }

            #region Nested type: SMDel

            private delegate void SMDel(ref Message M);

            #endregion
        }

        #endregion

        #region Nested type: SMDel

        private delegate void SMDel(ref Message M);

        #endregion
    }
}